package cn.zyl.common.redis.service.impl;

import cn.zyl.common.redis.service.JedisConnectApi;
import cn.zyl.common.redis.enums.RedisDataEnum;
import cn.zyl.demo.common.tools.StringTool;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * JedisClusterConnectApiImpl类说明:
 *
 * @author wsz
 * @version v1.0
 * @date 2020-08-05
 */
public class JedisClusterConnectApiImpl implements JedisConnectApi {
    private final JedisCluster jedis;
    private final String host;
    public JedisClusterConnectApiImpl(JedisCluster jedis,String host){
        this.jedis = jedis;
        this.host = host;
    }
    /**
     * 获取单独的redis客户端
     * @return redis客户端
     */
    private Jedis getJedis(){
        return jedis.getClusterNodes().get(host).getResource();
    }
    /**
     * ping连接redis服务器
     * @param message 消息
     * @return 消息
     */
    @Override
    public String ping(String message) {
        Jedis node = getJedis();
        String res = StringTool.isEmpty(message)?node.ping():node.ping(message);
        node.close();
        return res;
    }
    /**
     * 获取redis，有关服务器的信息和统计数据
     * @param section 消息
     * @return 消息
     */
    @Override
    public String info(String section) {
        Jedis node = getJedis();
        String res = StringTool.isEmpty(section)?node.info():node.info(section);
        node.close();
        return res;
    }
    /**
     * 将字符串值设置为键的值
     * @param key   键
     * @param value 值
     * @return 状态码回复
     */
    @Override
    public String set(String key, String value) {
        return StringTool.isEmpty(key) ? null : jedis.set(key,value);
    }
    /**
     * 获取指定键的值。 如果该键不返回则为null。 如果存储在关键值不返回一个错误，因为GET只能处理字符串值的字符串。
     * @param key 键
     * @return 值
     */
    @Override
    public Map<String, Object> get(String key) {
        Map<String, Object> map = new HashMap<>(6);
        map.put("key", key);
        if(StringTool.isNotEmpty(key) && jedis.exists(key)){
            key2info(map, key);
        }else {
            map.put("exists", "不能存在");
        }
        return map;
    }
    /**
     * 使用"cluster slots"指令获取Cluster节点和槽的映射关系
     * @return 映射关系
     */
    @Override
    public List<Object> slots(){
        Jedis node = getJedis();
        List<Object> res = node.clusterSlots();
        node.close();
        return res;
    }
    /**
     * 随机获取key，并返回相关信息
     * @return key相关信息
     */
    @Override
    public Map<String, Object> randomKey(){
        Map<String, Object> map = new HashMap<>(6);
        Jedis node = getJedis();
        String key = node.randomKey();
        key2info(map, key);
        node.close();
        return map;
    }
    /**
     * scan命令扫描redis的key空间
     * @param cursor 数字，第一次为 0 ，扫描redis的游标，SCAN 命令每次被调用之后， 都会向用户返回一个新的游标
     * @param match 正则匹配key,全部为 *，建议前缀正则如：key*
     * @param count 每次扫描的个数
     * @return 扫描结果，含新的游标，如果返回游标为0说明扫描结束
     */
    @Override
    public Map<String, Object> scan(String cursor,String match,Integer count){
        Map<String, Object> map = new HashMap<>(8);
        ScanParams params = new ScanParams();
        params.match(match);
        params.count(count);
        //redis命令scan：scan 游标 match 正则 count 条数
        ScanResult<String> result = getJedis().scan(cursor, params);
        //返回的游标
        map.put("cursor-new", result.getCursor());
        List<String> list = new ArrayList<>(result.getResult());
        map.put("list", list);
        return map;
    }
    private void key2info(Map<String, Object> map,String key){
        String type = jedis.type(key);
        map.put("key", key);
        map.put("type", type);
        map.put("ttl", jedis.ttl(key));
        if(RedisDataEnum.STRING.eq(type)){
            map.put("val", jedis.get(key));
        }else if (RedisDataEnum.HASH.eq(type)){
            map.put("h.len", jedis.hlen(key));
            map.put("h.val",jedis.hgetAll(key));
        }else if (RedisDataEnum.LIST.eq(type)){
            map.put("l.len", jedis.llen(key));
            map.put("l.v-0-end", jedis.lrange(key, 0, Long.parseLong(map.get("l.len").toString())));
        }else if (RedisDataEnum.SET.eq(type)){
            map.put("s.len", jedis.scard(key));
            map.put("s.rand", jedis.smembers(key));
        }else if (RedisDataEnum.Z_SET.eq(type)){
            map.put("z.len", jedis.zcard(key));
            map.put("z.0-10", jedis.zrange(key, 0L, 10L));
        }
    }
}
